"""
文本比对类，仅对文本差异化进行比较
"""

import copy
import numpy as np
from TestToolsV2.common.ActivityDatas import activityDatas
from TestToolsV2.tools.Log import Log

log = Log()


class checkContent:
    def __init__(self, _activityDatas: activityDatas):
        self.activityDatas: activityDatas = _activityDatas

    def PrintData(self):
        log.Show("----------------------interpretingData----------------------")
        log.Show(self.activityDatas.reEditText, 20, "reEditText")
        log.Show(self.activityDatas.taEditText, 20, "taEditText")
        log.Show(self.activityDatas.colorKey, 20, "colorKey")
        log.Show(self.activityDatas.reAllInfo, 20, "reAllInfo")
        log.Show(self.activityDatas.taAllInfo, 20, "taAllInfo")
        log.Show(self.activityDatas.reDiffInfo, 40, "reDiffInfo")
        log.Show(self.activityDatas.taDiffInfo, 40, "taDiffInfo")
        log.Show(self.activityDatas.offsetIndex, 40, "offsetIndex")

    def do_checkContent(self):
        """
        文本比对，并设置展示内容,返回true表示操作成功
        """
        # 判断两个框中的文本是否相同（长度相同，内容相同）
        if self.__isEqual():  # 如果相同
            # 设置相同时展示的详细内容
            self.__addSameInfo('<br />'.join(self.activityDatas.reEditText.splitlines()),
                               '<br />'.join(self.activityDatas.taEditText.splitlines()))
            return True
        else:  # 如果不同
            # 设置差异化展示标记
            self.activityDatas.colorKey = 1
            # 处理差异化字符串内容，并添加到展示信息内容中
            self.__setDifferentInfo(self.activityDatas.reEditText, self.activityDatas.taEditText)
            return False

    def __isEqual(self):
        """
        比对两组数据中的字符串是否相同\n
        :return: 相等返回 True
        """
        resource, target = self.activityDatas.reEditText, self.activityDatas.taEditText
        if len(resource) != len(target):
            return False
        if resource == target:
            return True
        else:
            return False

    def __addSameInfo(self, resource, targer):
        """
        设置相同内容比对详情\n
        :param resource: 比对源字符串
        :param targer: 比对目标字符串
        """
        self.activityDatas.reAllInfo.append(f"{resource}<br />")
        self.activityDatas.taAllInfo.append(f"{targer}<br />")

    def __addDifferent(self, myre, myta):
        resourceInfo, targetInfo = self.__getDiffLengthDiff(myre, myta)
        self.activityDatas.reAllInfo.append(f"{''.join(resourceInfo)}")
        self.activityDatas.taAllInfo.append(f"{''.join(targetInfo)}")
        self.activityDatas.reDiffInfo.append(f"{''.join(resourceInfo)}")
        self.activityDatas.taDiffInfo.append(f"{''.join(targetInfo)}")

    def __setDifferentInfo(self, resource, targer):
        """
        处理差异化字符串内容，并添加到展示信息内容中\n
        :param resource: 源字符串
        :param targer: 目标字符串
        """
        relist = resource.splitlines()
        talist = targer.splitlines()
        rel = len(relist)
        tal = len(talist)
        length = rel
        offset = 0
        key = True

        if rel > tal:
            length = tal
            offset = rel - tal
            key = True
        elif rel < tal:
            length = rel
            offset = tal - rel
            key = False

        for i in range(length):
            reline, taline = relist[i].strip(), talist[i].strip()
            # 先判断字符串长度是否【不一致】,内容部分存在空格也属于不一致
            if len(reline) != len(taline):
                self.__addDifferent(reline, taline)
            else:
                # 如果长度一致，在简单判断字符串整体是否【不一致】
                if reline != taline:
                    self.__addDifferent(reline, taline)
                else:
                    # 如果整体内容一致，那么就肯定一致了
                    self.activityDatas.reAllInfo.append(f"{reline}")
                    self.activityDatas.taAllInfo.append(f"{taline}")

        if offset > 0:
            for i in range(offset):
                if key:
                    self.activityDatas.reAllInfo.append(
                        f"{self.activityDatas.mark.markT(f'倒数第 {i + 1} 行 多出来了！')}<br /> {self.activityDatas.mark.markT(relist[-i])}<br />")
                else:
                    self.activityDatas.taAllInfo.append(
                        f"{self.activityDatas.mark.markT(f'倒数第第 {i + 1} 行 多出来了！')}<br /> {self.activityDatas.mark.markT(talist[-i])}<br />")

    def __lev_distance(self, resour, target):
        """
        获取字符串最短编辑距离（如果有一个字符存在差异，则编辑距离为1，以此类推，差异越大，编辑距离就越大）\n
        :param resour: 源数据
        :param target: 目标数据
        :return: 返回两组字符串之间的最短编辑距离
        """
        bArray = np.array(np.arange(len(target) + 1))  # 创建1维数组，长度比B多1
        for i in range(1, len(resour) + 1):
            temp1 = bArray[0]
            bArray[0] += 1
            for j in range(1, len(target) + 1):
                temp2 = bArray[j]
                if resour[i - 1] == target[j - 1]:
                    bArray[j] = temp1
                else:
                    bArray[j] = min(temp1, min(bArray[j - 1], bArray[j])) + 1
                temp1 = temp2
        return bArray[len(target)]

    def __getSameLengthDiff(self, resour, target):
        """
        获取相同长度时的差异化展示数据\n
        :param resour: 源数据
        :param target: 目标数据
        :return: 返回标记后的差异化数据列表
        """
        indexList = self.__findDiffAll(resour, target)
        _relist = list(resour)
        _talist = list(target)
        for i in range(len(resour)):
            if i in indexList:
                _relist[i], _talist[i] = self.activityDatas.mark.markT(_relist[i]), self.activityDatas.mark.markT(
                    _talist[i])
        return _relist, _talist

    def __findDiffAll(self, resour, target):
        """
        查找所有不同位置的下标\n
        :param resour: 源数据
        :param target: 目标数据
        :return: 返回第所有差异字符的下标
        """
        length_r = len(resour)
        length_t = len(target)
        indexList = []
        for i in range(length_r):
            if resour[i] != target[i]:
                indexList.append(i)
        if length_r < length_t:
            offset = length_t - length_r
            for x in range(offset):
                indexList.append(length_r + x)
        return indexList

    def __getDiff(self, _reList, _taList):
        # 获取首次比对数据结果
        myLev, myOffSet, myDiffCount = self.__getDataForLev(_reList, _taList)
        # 初始化临时列表
        reTempList = copy.deepcopy(_reList)
        # 获取所有差异位置下标
        allDiffIndex = self.__findDiffAll(_reList, _taList)
        allLength = len(allDiffIndex)
        for i in range(allLength):
            diffI = allDiffIndex[i]
            # 将目标字符串相同位置的字符插入到比对源字符串中
            if _taList[diffI] == '[':
                reTempList.insert(diffI, ' ')
            elif _taList[diffI] == ']':
                reTempList.insert(diffI, ' ')
            else:
                reTempList.insert(diffI, _taList[diffI])
            # 获取插值后的比对数据结果
            newLev, newOffset, newDiffCount = self.__getDataForLev(reTempList, _taList)
            # 新的编辑距离如果比旧大，说明插入位置不对
            if newLev > myLev:
                # 初始化临时列表
                reTempList.clear()
                reTempList = copy.deepcopy(_reList)
            # 新编辑距离如果小于或者等于旧的
            else:
                # 还需要判断差异量，如果新差异量大于旧差异量，说明位置还是不正确
                if newDiffCount > myDiffCount:
                    # 初始化临时列表
                    reTempList.clear()
                    reTempList = copy.deepcopy(_reList)
                # 只有新编辑距离小于等于，且新差异量小于等于旧数据时，才算正确
                else:
                    # 将正确的下标添加到正确下标列表中
                    self.activityDatas.offsetIndex.append(diffI)
                    return list(reTempList), newOffset

    def __getDataForLev(self, resour, target):
        """
        通过最短编辑距离，获取两组字符串之间的差异化数据\n
        :param resour: 源数据
        :param target: 目标数据
        :return: 返回最短编辑距离，字符串之间的长度偏移量，差异化字符量
        """
        _offset = len(target) - len(resour)
        _lev = self.__lev_distance(resour, target)
        _diffCount = _lev - _offset
        return _lev, _offset, _diffCount

    def __getDiffLengthDiff(self, resour, target):
        reverse = False
        reList, taList = [], []
        if len(resour) > len(target):
            reList, taList = list(target), list(resour)
            reverse = True
        elif len(resour) < len(target):
            reList, taList = list(resour), list(target)
        elif len(resour) == len(target):
            reList, taList = self.__getSameLengthDiff(resour, target)
            return reList, taList
        # 获取首次比对数据结果
        lev, offset, diffCount = self.__getDataForLev(reList, taList)
        newList = copy.deepcopy(reList)
        # 循环进行插值，找到正确插值下标，当返回的偏移量为0时，说明插值都已经正确
        try:
            while offset != 0:
                newList, offset = self.__getDiff(newList, taList)
        except TypeError as e:
            log.Show(e, 40)
            log.Show(f'{newList}', 40, 'GetDiffLengthDiff():newList')
            log.Show(f'{offset}', 40, 'GetDiffLengthDiff():offset')

        # 经过插值部位后，短字符串长度和长字符串相同，这时再为差异部分做标记
        newList, taList = self.__getSameLengthDiff(newList, taList)
        # 将短字符串插值的下标记录下来，逆向排列，后面需要按照这个插值下标将插值去除
        self.activityDatas.offsetIndex = self.activityDatas.offsetIndex[::-1]
        # log.Show(f'{newList}', 30, 'newList')
        # log.Show(offsetIndex, 30, "offsetIndex ")
        # 通过逆向坐标去除插值，还原字符串
        reList = copy.deepcopy(newList)
        for index in self.activityDatas.offsetIndex:
            del reList[index]
            taList[index] = self.activityDatas.mark.markT(taList[index])

        # 如若反转字符串标记为真，则将源字符串和目标字符串反转
        if reverse:
            reList, taList = taList, reList
        return reList, taList
